//
// Created by 周杰 on 2020/1/14.
//

#include "AdvanceWorkTest.h"

const string image_path = "/Volumes/D/study/machinelearning/opencv/testpic/fangzi1.jpeg";
//const string image_path = "/Volumes/D/study/machinelearning/opencv/testpic/loufang.jpg";

/**
 * 进行直线检测，使用霍夫概率检测，这样提取效果好些
 * 1。图片转灰度
 * 2。图片进行分割提取主体
 * 3。进行边缘的检测
 * 4。检测直线
 */
void AdvanceWorkTest::lineDetectTest() {
    Mat source_image = imread(image_path);
    imshow("source image.", source_image);

    //进行灰度变换
    Mat gray_image;
    cvtColor(source_image, gray_image, COLOR_BGR2GRAY);
    imshow("gray image.", gray_image);
    //进行图片阀值化
    Mat biary_image;
    threshold(gray_image, biary_image, 150, 0xff, ThresholdTypes::THRESH_OTSU);
    imshow("binary image.", biary_image);
    //提取边缘
    Mat canny_image;
    Canny(biary_image, canny_image, 30, 120);
    imshow("canny image.", canny_image);
    //进行霍夫直线检测
    vector<Vec4f> lines;
    HoughLinesP(canny_image, lines, 1, CV_PI / 180, 5);
    printf("line nums: %d \n", lines.size());
    for (int i = 0; i < lines.size(); ++i) {
        line(source_image, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(0, 0, 255), 2);
    }
    imshow("line result.", source_image);

    waitKey();
    destroyAllWindows();
}

/**
 * 通过harris角点检测  归一化后的处理
 *
 * 发现效果并不好，在实物图像中好多角点都没出来
 */
void AdvanceWorkTest::harrisDetect1() {
    Mat source_image = imread(image_path);
    imshow("source image.", source_image);

    //图像灰度处理
    Mat gray_image;
    cvtColor(source_image, gray_image, COLOR_BGR2GRAY);
    imshow("gray image.", gray_image);

    //Harris角点检测
    Mat harris_image;
    cornerHarris(gray_image, harris_image, 2, 3, 0.04);
    imshow("harris image.", harris_image);
    //归一化
    Mat normal_image;
    normalize(harris_image, normal_image, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
    Mat scaled_image;
    convertScaleAbs(normal_image, scaled_image);
    imshow("scaled image.", scaled_image);
    Mat h_cor_result = source_image.clone();
    //rows就是行，cols就是列
    for (int i = 0; i < scaled_image.cols; ++i) {
        for (int j = 0; j < scaled_image.rows; ++j) {
            float value = normal_image.at<float>(i, j);
            if ((int) value < 85) {
                continue;
            }
            printf("value: %f \n", value);
            circle(h_cor_result, Point(j, i), 2, Scalar(0, 0, 255));
        }
    }
    imshow("harris result.", h_cor_result);

    waitKey();
    destroyAllWindows();
}

/**
 * 1.转换图片灰度
 * 2.将灰度图片进行角点检测
 * 3.获取检测的焦点里边的最大值和最小值
 * 4.将角点检测结果进行膨胀然后和原检测结果进行比较提取都有的地方
 * 5.根据检测结果中的最大值乘0.05获取图片的阀值
 * 6.根据获取的阀值进行图片的二值化，获取焦点
 * 7.将阀值化的结果与compare提取的结果进行与操作
 * 8.再将获取的结果与阀值化的结果进行与操作，获取角点
 */
void AdvanceWorkTest::harrisDetect2() {
    Mat source_image = imread(image_path);
    imshow("source image.", source_image);

    //灰度转换
    Mat gray_image;
    cvtColor(source_image, gray_image, COLOR_BGR2GRAY);

    //角点检测
    Mat harris_image;
    // 最后一个参数k一般取 0.04~0.06之间
    cornerHarris(gray_image, harris_image, 3, 3, 0.04);
    imshow("harris ori image.", harris_image);

    //对获取的点做处理
    double minStrength, maxStrength;
    //找到最大致和最小值
    minMaxLoc(harris_image, &minStrength, &maxStrength);
    printf("min: %lf max: %lf \n", minStrength, maxStrength);
    //进行膨胀
    Mat dilate_image;
    dilate(harris_image, dilate_image, Mat());
    imshow("dilate image.", dilate_image);
    //获得相同的部分
    Mat eq_image;
    compare(harris_image, dilate_image, eq_image, CmpTypes::CMP_EQ);
    imshow("compare image.", eq_image);

    //角点的阀值
    double tV = maxStrength * 0.05;
    Mat binary_image;
    threshold(harris_image, binary_image, tV, 0xff, THRESH_BINARY);
    imshow("binary image", binary_image);
    //转换成8位图片
    Mat cornerMap, result;
    binary_image.convertTo(cornerMap, CV_8U);
    binary_image.convertTo(result, CV_8U);
    imshow("bit 8 result", result);
    //进行非极大值抑制
    bitwise_and(cornerMap, eq_image, cornerMap);
    bitwise_and(result, cornerMap, result);
    imshow("corner map image.", cornerMap);
    //绘制角点
    for (int i = 0; i < cornerMap.rows; ++i) {
        uchar *r = cornerMap.ptr<uchar>(i);
        for (int j = 0; j < cornerMap.cols; ++j) {
            if (r[j]) {
                circle(source_image, Point(j, i), 2, Scalar(0, 0, 255));
            }
        }
    }
    imshow("result", source_image);

    waitKey();
    destroyAllWindows();
}

/**
 * 角点检测流程：
 * 1.创建算子
 * 2.检测
 * 3.提取描述
 * 4.匹配
 */
void AdvanceWorkTest::advanceTest() {
    Mat source_image = imread(image_path);
    imshow("source image.", source_image);

    //fast检测
    vector<KeyPoint> keypoints;
    Ptr<FastFeatureDetector> fast = FastFeatureDetector::create(40);
    fast->detect(source_image, keypoints);
    Mat fast_result_image = source_image.clone();
    drawKeypoints(fast_result_image, keypoints, fast_result_image, Scalar(0, 0, 255), DrawMatchesFlags::DRAW_OVER_OUTIMG);
    imshow("result image.", fast_result_image);

    //SIFT算法
    vector<KeyPoint> siftpoints;
    Ptr<SIFT> sift = xfeatures2d::SIFT::create(600);
    sift->detect(source_image,siftpoints);
    Mat sift_result_image = source_image.clone();
    drawKeypoints(sift_result_image,siftpoints,sift_result_image,Scalar(0,0,255),cv::DrawMatchesFlags::DRAW_OVER_OUTIMG);
    imshow("sift result image.",sift_result_image);

    //ORB算法
    vector<KeyPoint> orbpoints;
    Ptr<ORB> orb = ORB::create(600);
    orb->detect(source_image,orbpoints);
    Mat orb_result_image = source_image.clone();
    drawKeypoints(orb_result_image,orbpoints,orb_result_image,Scalar(0,0,255),cv::DrawMatchesFlags::DRAW_OVER_OUTIMG);
    imshow("orb result image.",orb_result_image);

    //匹配，仅仅测试api
    //寻找描述

    Mat sift_desc;
    sift->compute(source_image,siftpoints,sift_desc);
    Mat sift_desc2;
    sift->compute(source_image,siftpoints,sift_desc2);
    //创建描述的匹配
    Ptr<DescriptorMatcher> macher = DescriptorMatcher::create("BruteForce");
    vector<DMatch>matchs;
    macher->match(sift_desc,sift_desc2,matchs);
    //清除掉部分点方便查看更清晰
    matchs.erase(matchs.begin()+25,matchs.end());
    //获取画描述点的图像
    Mat match_img;
    drawMatches(source_image,siftpoints,source_image,siftpoints,matchs,match_img);
    imshow("match img.",match_img);

    waitKey();
    destroyAllWindows();
}